/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.repository.adaptor;

import com.inspur.edp.cef.api.RefObject;
import com.inspur.edp.cef.api.repository.*;
import com.inspur.edp.cef.api.repository.adaptor.INestedAdaptor;
import com.inspur.edp.cef.api.repository.readerWriter.ICefReader;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.repository.adaptoritem.dbprocessor.DbProcessor;
import com.inspur.edp.cef.repository.adaptoritem.dbprocessor.DbProcessorFactory;
import com.inspur.edp.cef.repository.assembler.nesteddatatype.NestedColumnInfo;
import com.inspur.edp.cef.repository.exception.CefRepositoryException;

import java.util.HashMap;

public abstract class NestedAdaptor extends DataTypeAdapter implements INestedAdaptor
{
	private DbProcessor dbProcessor;
	private HashMap<String, INestedRepository> nestedRepositories = new HashMap<>();
	private final Object netstRepositoryLock = new Object();
	public NestedAdaptor()
	{
		initColumnCache();
		initReaders();
	}

	private void initColumnCache(){
		if(NestedColumnManager.getInstance().getInitMap().get(this.getClass().getName()) ==null || !NestedColumnManager.getInstance().getInitMap().get(this.getClass().getName())){
			synchronized (NestedColumnManager.getInstance().getInitMap()){
				if(NestedColumnManager.getInstance().getInitMap().get(this.getClass().getName()) ==null || !NestedColumnManager.getInstance().getInitMap().get(this.getClass().getName())){
					initColumns();
					NestedColumnManager.getInstance().getInitMap().put(this.getClass().getName(), true);
				}
			}
		}
	}

//	private java.util.HashMap<String, NestedColumnInfo> columns = new java.util.HashMap<String, NestedColumnInfo>();
	private java.util.ArrayList<INestedDataReader> dataReaders = new java.util.ArrayList<INestedDataReader>();
	protected final void addColumnInfo(String columnName, INestedPersistenceValueReader persistenceValueReader, boolean isMultiLang, boolean isUdt, boolean isAssociation, boolean isEnum, String belongElementLabel) {
		NestedColumnManager.getInstance().addColumnInfo(this.getClass().getName(), columnName, persistenceValueReader, isMultiLang, isUdt, isAssociation, isEnum, belongElementLabel);
//		NestedColumnInfo tempVar = new NestedColumnInfo();
//		tempVar.setColumnName(columnName);
//		tempVar.setBelongElementLabel(belongElementLabel);
//		tempVar.setIsAssociation(isAssociation);
//		tempVar.setIsEnum(isEnum);
//		tempVar.setIsAssociateRefElement(false);
//		tempVar.setIsMultiLang(isMultiLang);
//		tempVar.setIsUdtElement(isUdt);
//		tempVar.setPersistenceValueReader(persistenceValueReader);
//		columns.put(columnName, tempVar);
	}
	public final DbProcessor getDbProcessor(){
		if(dbProcessor == null)
			dbProcessor = DbProcessorFactory.getDbProcessor();
		return dbProcessor;
	}
	protected final void addDataReader(INestedDataReader reader)
	{
		dataReaders.add(reader);
	}

	protected abstract void initColumns();

	protected abstract void initReaders();

	private INestedRepository privateBelongRepository;
	public final INestedRepository getBelongRepository()
	{
		return privateBelongRepository;
	}
	public final void setBelongRepository(INestedRepository value)
	{
		privateBelongRepository = value;
	}
	private String getFirstColumnName()
	{
		for (String item : NestedColumnManager.getInstance().getColumns(this.getClass().getName()).keySet())
		{
			return item;
		}
		throw new CefRepositoryException("");
	}
	public final ICefData readData(ICefReader reader)
	{
		return createInstance(reader);
	}

	@Override
	public ICefData createInstance(ICefReader reader)
	{
		ICefData data = getBelongRepository().getManager().createDataType();

		for (INestedDataReader item : dataReaders)
		{
			RefObject<ICefData> tempRef_data = new RefObject<ICefData>(data);
			item.readData(tempRef_data, reader);
			data = tempRef_data.argvalue;
		}
		return data;
	}

	@Override
	public Object getPersistenceValue(String colName, ICefData data)
	{
		return getPersistenceValue(colName, data, true);
	}

	@Override
	public final Object getPersistenceValue(String colName, ICefData data, boolean isNull) {
		if(colName==null||"".equals(colName))
			colName =	this.getFirstColumnName();
		INestedPersistenceValueReader valueReader = NestedColumnManager.getInstance().getColumns(this.getClass().getName()).get(colName).getPersistenceValueReader();
		if(valueReader instanceof INullableNestedPersistenceValueReader){
			return ((INullableNestedPersistenceValueReader)valueReader).getPersistenceValue(data, isNull);
		}else {
			return valueReader.getPersistenceValue(data);
		}
	}

	@Override
	public String getTableNameByColumns(java.util.HashMap<String, String> columns, String keyColumnName, RefObject<String> keyDbColumnName, java.util.ArrayList<String> tableAlias)
	{
		throw new UnsupportedOperationException();
	}

	@Override
	public String getTableNameByRefColumns(java.util.HashMap<String, RefColumnInfo> columns, String keyColumnName, RefObject<String> keyDbColumnName, java.util.ArrayList<String> tableAlias)
	{
		throw new UnsupportedOperationException();
	}

	@Override
	public String getTableNameByRefColumns(TableNameRefContext tableNameRefContext){
		throw new UnsupportedOperationException();
	}

	protected INestedRepository getNestedRepository(String configId){
		if(!nestedRepositories.containsKey(configId)){
			synchronized (netstRepositoryLock){
				if(!nestedRepositories.containsKey(configId)){
					nestedRepositories.put(configId, com.inspur.edp.udt.api.UdtManagerUtils.getUdtRepositoryFactory().createRepository(configId));
				}
			}
		}
		return nestedRepositories.get(configId);
	}

	public java.util.HashMap<java.lang.String,java.lang.String> getAssosPropDBMapping(java.lang.String propName)
	{
		return new HashMap<>();
	}

}
